/*
 * implementation for top level data structure.
 *
 * implemented as a simple binary tree.
 */

#include <string.h>
#include "schemebase.h"
#include "toplevel.h"
#include "schemeobject.h"
#include "env.h"

typedef struct SymbolNode
{
  SymbolEntry* sym ;
  struct SymbolNode* left ;
  struct SymbolNode* right ;
} SymbolNode ;

#define NODE_ENTRY(symNode)     ((symNode)->sym)
#define NODE_NAME(symNode)      (NODE_ENTRY(symNode)->name)
#define NODE_HAS_VALUE(symNode) (NODE_ENTRY(symNode)->isDefined)
#define NODE_VALUE(symNode)     (NODE_ENTRY(symNode)->sob)
#define NODE_LEFT(symNode)      ((symNode)->left)
#define NODE_RIGHT(symNode)     ((symNode)->right)

SymbolNode* topLevel = NULL;

SymbolEntry *probeForSymbolRecursive(string name, SymbolNode *t)
{
	int compare;

	if (t == NULL)
	{
		return NULL;
	}

	compare = strcmp(name, NODE_NAME(t));
	if (compare == 0) {
		return NODE_ENTRY(t);
	} else if (compare < 0) {
		return probeForSymbolRecursive(name, NODE_LEFT(t));
	} else {
		return probeForSymbolRecursive(name, NODE_RIGHT(t));
	}
}

SymbolNode* newSymbolNode(string name);

SymbolEntry* getSymbolRecursive(string name, SymbolNode* t)
{
	int compare;
	SymbolNode* child;

	if (t == NULL)
	{
		if (t == topLevel)
		{
			topLevel = newSymbolNode(name);
			return NODE_ENTRY(topLevel);
		}
		else
		{
			RUNTIME_ASSERT(t != NULL);
		}
	}

	compare = strcmp(name, NODE_NAME(t));

	if (compare == 0) {
		return NODE_ENTRY(t);
	} else if (compare < 0) {
		child = NODE_LEFT(t);
		if (child == NULL)
		{
			child = newSymbolNode(name);
			NODE_LEFT(t) = child;
			return NODE_ENTRY(child);
		}
		else
		{
			return getSymbolRecursive(name, child);
		}
	} else {
		child = NODE_RIGHT(t);
		if (child == NULL)
		{
			child = newSymbolNode(name);
			NODE_RIGHT(t) = child;
			return NODE_ENTRY(child);
		}
		else
		{
			return getSymbolRecursive(name, child);
		}
	}
}

SymbolEntry* probeForSymbol(string name)
{
	return probeForSymbolRecursive(name, topLevel) ;
}

SymbolEntry* getSymbol(string name)
{
	return getSymbolRecursive(name, topLevel) ;
}

SymbolNode* newSymbolNode(string name)
{
	SymbolNode* child;

	child = (SymbolNode*)autoMalloc(sizeof(SymbolNode));
	NODE_ENTRY(child) = (SymbolEntry*)autoMalloc(sizeof(SymbolEntry));
	NODE_NAME(child) = stringCopy(name);
	strcpy(NODE_NAME(child), name);
	NODE_HAS_VALUE(child) = FALSE;
	NODE_VALUE(child) = NULL;
	NODE_LEFT(child) = NODE_RIGHT(child) = NULL;

	return child;
}

void bindToGlobalEnv (string name, MachineCode code)
{
	SymbolEntry* s = getSymbol (name);
	s->isDefined = TRUE;
	s->sob = makeSchemeClosure(emptyEnv, code);
}
